package com.example.core.request;

import com.example.common.constants.BasicConst;
import com.example.common.util.TimeUtil;
import com.google.common.collect.Lists;
import com.jayway.jsonpath.JsonPath;
import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.cookie.Cookie;
import io.netty.handler.codec.http.cookie.ServerCookieDecoder;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.asynchttpclient.Request;
import org.asynchttpclient.RequestBuilder;

import java.nio.charset.Charset;
import java.util.*;

/**
 * @Author Peng Yisheng
 * @Date 2024/11/4 23:28
 * @Description 网关请求类
 */
@Slf4j
public class GatewayRequest implements IGatewayRequest {
    @Getter
    private final String uniqueId;  // 服务ID

    @Getter
    private final long beginTime;  // 请求进入网关时间

    @Getter
    private final Charset charset;  // 字符集

    @Getter
    private final String clientIp;  // 客户端IP, 用于做流控, 黑白名单

    @Getter
    private final String host;  // 请求的地址, ip:port

    @Getter
    private final String path;  // 请求路径  /xxx/xxx/xx

    @Getter
    private final String uri;  // /XXX/XXX/XXX?attr1=value&attr2=value2

    @Getter
    private final HttpMethod method;  // 请求方法

    @Getter
    private final String contentType;  // 请求的格式

    @Getter
    private final HttpHeaders headers;  // 请求头信息

    @Getter
    private final QueryStringDecoder queryStringDecoder;  // 参数解析器

    @Getter
    private final FullHttpRequest fullHttpRequest;  // netty FullHttpRequest

    @Getter
    private String body;  // 请求体

    @Getter
    private boolean gray;  // 是否灰度流量

    @Setter
    @Getter
    private long userId;

    @Getter
    private Map<String, Cookie> cookieMap;  // 请求Cookie

    @Getter
    private Map<String, List<String>> postParameters;  // post请求参数集合


    private String modifyScheme;  // 可修改的Scheme，默认是http://
    private String modifyHost;
    private String modifyPath;

    private final RequestBuilder requestBuilder;  // 用于构建下游请求的http构建器

    public GatewayRequest(String uniqueId, Charset charset,
                          String clientIp, String host, String uri,
                          HttpMethod method, String contentType, HttpHeaders headers,
                          FullHttpRequest fullHttpRequest, boolean gray) {
        this.uniqueId = uniqueId;
        this.beginTime = TimeUtil.currentTimeMillis();
        this.charset = charset;
        this.clientIp = clientIp;
        this.host = host;
        this.uri = uri;
        this.method = method;
        this.contentType = contentType;
        this.headers = headers;
        this.fullHttpRequest = fullHttpRequest;
        this.gray = gray;
        this.queryStringDecoder = new QueryStringDecoder(uri, charset);
        this.path = queryStringDecoder.path();
        this.modifyHost = host;
        this.modifyPath = path;

        this.modifyScheme = BasicConst.HTTP_PREFIX_SEPARATOR;
        this.requestBuilder = new RequestBuilder();
        this.requestBuilder.setMethod(getMethod().name());
        this.requestBuilder.setHeaders(getHeaders());
        this.requestBuilder.setQueryParams(queryStringDecoder.parameters());

        ByteBuf contentBuffer = fullHttpRequest.content();
        if (Objects.nonNull(contentBuffer)) {
            this.requestBuilder.setBody(contentBuffer.nioBuffer());
        }
    }

    public String getBody() {
        if (StringUtils.isEmpty(body)) {
            body = fullHttpRequest.content().toString(charset);
        }
        return body;
    }

    public Cookie getCookie(String name) {
        if (cookieMap == null) {
            cookieMap = new HashMap<>();
            String cookieStr = getHeaders().get(HttpHeaderNames.COOKIE);
            if (StringUtils.isBlank(cookieStr)) {
                return null;
            }
            Set<Cookie> cookies = ServerCookieDecoder.STRICT.decode(cookieStr);
            for (Cookie cookie : cookies) {
                cookieMap.put(cookie.name(), cookie);  // cookieMap.put(name,cookie); ?????
            }
        }
        return cookieMap.get(name);
    }

    public List<String> getQueryParametersMultiple(String name) {
        return queryStringDecoder.parameters().get(name);
    }

    public List<String> getPostParametersMultiples(String name) {
        String body = getBody();
        if (isFormPost()) {
            if (postParameters == null) {
                QueryStringDecoder paramDecoder = new QueryStringDecoder(body, false);
                postParameters = paramDecoder.parameters();
            }
            if (postParameters == null || postParameters.isEmpty()) {
                return null;
            } else {
                return postParameters.get(name);
            }
        } else if (isJsonPost()) {
            try {
                return Lists.newArrayList(JsonPath.read(body, name).toString());
            } catch (Exception e) {
                log.error("json path read failed: name={}, body={}", name, body, e);
            }
        }
        return null;
    }

    public boolean isFormPost() {
        return HttpMethod.POST.equals(method) &&
                (contentType.startsWith(HttpHeaderValues.FORM_DATA.toString()) ||
                        contentType.startsWith(HttpHeaderValues.APPLICATION_X_WWW_FORM_URLENCODED.toString()));
    }

    public boolean isJsonPost() {
        return HttpMethod.POST.equals(method) && contentType.startsWith(HttpHeaderValues.APPLICATION_JSON.toString());
    }

    @Override
    public void setModifyHost(String modifyHost) {
        this.modifyHost = modifyHost;
    }

    @Override
    public void setModifyPath(String modifyPath) {
        this.modifyPath = modifyPath;
    }

    @Override
    public void setHeader(CharSequence name, String value) {
        requestBuilder.setHeader(name, value);
    }

    @Override
    public void setRequestTimeout(int requestTimeout) {
        requestBuilder.setRequestTimeout(requestTimeout);
    }

    @Override
    public String getModifyHost() {
        return this.modifyHost;
    }

    @Override
    public String getModifyPath() {
        return this.modifyPath;
    }

    @Override
    public String getFinalUrl() {
        return modifyScheme + modifyHost + modifyPath;
    }

    @Override
    public void addHeader(CharSequence name, String value) {
        requestBuilder.addHeader(name, value);
    }

    @Override
    public void addQueryParam(String name, String value) {
        requestBuilder.addQueryParam(name, value);
    }

    @Override
    public void addFormParam(String name, String value) {
        if (isFormPost()) {
            requestBuilder.addFormParam(name, value);
        }
    }

    @Override
    public void addOrReplaceCookie(org.asynchttpclient.cookie.Cookie cookie) {
        requestBuilder.addOrReplaceCookie(cookie);
    }

    @Override
    public Request build() {
        requestBuilder.setUrl(getFinalUrl());
        // 将鉴权拿到的userid，传递到下游
        requestBuilder.addHeader("userId", String.valueOf(userId));
        return requestBuilder.build();
    }
}
